We are migrating the bug tracker to github Issues. This is now the preferred way to report NASM bugs.

Self-registration is disabled due to spam issue (mail gorcunov@gmail.com or hpa@zytor.com to create an account)

Bug 3392955 - Document using __?NASM_IFDIRECTIVE?__ gotchas
Summary: Document using __?NASM_IFDIRECTIVE?__ gotchas
Status: CLOSED FIXED
Alias: None
Product: NASM
Classification: Unclassified
Component: Assembler (show other bugs)
Version: 3.00.xx
Hardware: All All
: Medium minor
Assignee: nobody
URL:
Depends on:
Blocks:
 
Reported: 2025-09-14 00:10 PDT by E. C. Masloch
Modified: 2025-09-14 04:10 PDT (History)
5 users (show)

Obtained from: Built from git using configure
Generated by: Human
Bug category: Documentation incorrect, Other, Unexpected or confusing behavior
Observed for: Development code
Regression: No
Regression since:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description E. C. Masloch 2025-09-14 00:10:48 PDT
Two points here:

1. The documentation refers to __?NASM_HAS_IFDIRECTIVE?__ but the actual smacro seems to be missing the "HAS_" part.

2. Combining __?NASM_IFDIRECTIVE?__ with %ifdirective in the obvious way won't work on older NASM versions. This is because the %ifdirective isn't detected as a valid conditional directive so there will be one too many %endif directives.

As a workaround, the use of %ifdirective can be put into an mmacro that's only called if __?NASM_IFDIRECTIVE?__ is defined. Alternatively, an %if can be used with %isdirective(...) - the %if is supported as a nested directive in the non-true conditional, despite using the unsupported %isdirective(...)

I would like for this to be documented in the manual.


test$ cat test1.asm

%ifdef __?NASM_IFDIRECTIVE?__
 %ifdirective %note
  %note foo
 %endif
%endif
test$ cat test2.asm
%macro bar 0
 %ifdirective %note
  %note foo
 %endif
%endmacro

%ifdef __?NASM_IFDIRECTIVE?__
 bar
%endif
test$ cat test3.asm

%ifdef __?NASM_IFDIRECTIVE?__
 %if %isdirective(%note)
  %note foo
 %endif
%endif
test$ nasm -v
NASM version 2.16.02rc2 compiled on Oct 12 2023
test$ nasm test1.asm -l /dev/stderr
test1.asm:6: error: `%endif': no matching `%if'
test$ nasm test2.asm -l /dev/stderr
     1                                  %macro bar 0
     2                                   %ifdirective %note
     3                                    %note foo
     4                                   %endif
     5                                  %endmacro
     6
     7                                  %ifdef __?NASM_IFDIRECTIVE?__
     8                                   bar
     9                                  %endif
test$ nasm test3.asm -l /dev/stderr
     1
     2                                  %ifdef __?NASM_IFDIRECTIVE?__
     3                                   %if %isdirective(%note)
     4                                    %note foo
     5                                   %endif
     6                                  %endif
test$ ~/proj/nasmtest/broken/nasm -v
NASM version 3.00rc3 compiled on Sep  9 2025
test$ ~/proj/nasmtest/broken/nasm test1.asm -l /dev/stderr
     1
     2                                  %ifdef __?NASM_IFDIRECTIVE?__
     3                                   %ifdirective %note
     4                                    %note foo
     4          ------------------       note: foo
     5                                   %endif
     6                                  %endif
test$ ~/proj/nasmtest/broken/nasm test2.asm -l /dev/stderr
     1                                  %macro bar 0
     2                                   %ifdirective %note
     3                                    %note foo
     4                                   %endif
     5                                  %endmacro
     6
     7                                  %ifdef __?NASM_IFDIRECTIVE?__
     8                                   bar
     2                              <1>  %ifdirective %note
     3                              <1>  %note foo
     3          ------------------  <1>  note: foo
     4                              <1>  %endif
     9                                  %endif
test$ ~/proj/nasmtest/broken/nasm test3.asm -l /dev/stderr
     1
     2                                  %ifdef __?NASM_IFDIRECTIVE?__
     3                                   %if %isdirective(%note)
     4                                    %note foo
     4          ------------------       note: foo
     5                                   %endif
     6                                  %endif
test$
Comment 1 H. Peter Anvin 2025-09-14 02:59:06 PDT
Fixed the macro name, __?NASM_HAS_IFDIRECTIVE?__ was intended.

I have to admit I don't really follow your request for the documentation. Perhaps you could submit a patch?

This does seem to be a general issue with new %if directives; perhaps it should be mentioned in the %if section in general, and point out that using the %is() functions would avoid that problem?
Comment 2 H. Peter Anvin 2025-09-14 03:02:35 PDT
Something like this might be a good way to do it:

%ifdef __?NASM_HAS_IFDIRECTIVE?__
% define has_directive(x) %isdirective(x)
% define has_function(x)  %isdef(x)
% define has_usable(x)    %isusable(x)
%else
% define has_directive(x) 0
% define has_function(x)  0
% define has_usable(x)    0
%endif

The %else clause could perhaps get further refined, but the complexity runs away pretty quickly.
Comment 3 E. C. Masloch 2025-09-14 03:18:45 PDT
> This does seem to be a general issue with new %if directives; perhaps it
> should be mentioned in the %if section in general, and point out that using
> the %is() functions would avoid that problem?

Yes, exactly like that. I imagined putting this with the documentation of either %ifdirective or __?NASM_HAS_IFDIRECTIVE?__ but it would fit with %if generally too.

Your % define has_directive(x) %isdirective(x) workaround can also be used, yes.
Comment 4 H. Peter Anvin 2025-09-14 03:30:40 PDT
It obviously won't help the past, but I decided that going forward (especially going with the 3.xx major number :)) it is best to try to heuristically treat an unknown preprocessor directive beginning with %if or %elif as a conditional which should be balanced against %endif.

It seems to be a reasonable thing to do.
Comment 5 E. C. Masloch 2025-09-14 03:31:44 PDT
Yes, that's a good idea too.
Comment 6 E. C. Masloch 2025-09-14 03:45:55 PDT
Found another workaround: Use an %elifdirective. It won't be detected as a conditional directive by older NASM but the %if... to %endif ratio is preserved.

test$ cat test2.asm
%ifdef __?NASM_HAS_IFDIRECTIVE?__
 %if 0
 %elifdirective %note
  %note quux
 %endif
%endif
test$ nasm -v
NASM version 2.16.02rc2 compiled on Oct 12 2023
test$ nasm test2.asm -l /dev/stderr
     1                                  %ifdef __?NASM_HAS_IFDIRECTIVE?__
     2                                   %if 0
     3                                   %elifdirective %note
     4                                    %note quux
     5                                   %endif
     6                                  %endif
test$ ~/proj/nasmtest/broken/nasm -v
NASM version 3.00rc4 compiled on Sep 14 2025
test$ ~/proj/nasmtest/broken/nasm test2.asm -l /dev/stderr
     1                                  %ifdef __?NASM_HAS_IFDIRECTIVE?__
     2                                   %if 0
     3                                   %elifdirective %note
     4                                    %note quux
     4          ------------------       note: quux
     5                                   %endif
     6                                  %endif
test$
Comment 7 H. Peter Anvin 2025-09-14 04:10:37 PDT
Well, I did my best and wrote some documentation.